#ifndef TEMPLE_THIRD_FASTCGI_H_
#define TEMPLE_THIRD_FASTCGI_H_

#include "util/stdc.h"
#include "fcgi_config.h"
#include "fcgiapp.h"

class FcgiRequest
{
public:
    inline FcgiRequest(const FCGX_Request &fcgx_req)
    {
        this->fcgx_req = fcgx_req;
    }

    inline int get_param(const char *name, string &value)
    {
        char *param = FCGX_GetParam(name, fcgx_req.envp);
        if (!param)
            return 1;

        value = param;
        return 0;
    }

    inline int get_str(char *buf, int len)
    {
        return FCGX_GetStr(buf, len, fcgx_req.in);
    }

    inline int put_str(const char *buf, int len)
    {
        return FCGX_PutStr(buf, len, fcgx_req.out);
    }

private:
	FCGX_Request fcgx_req;
};

class FcgiAgent
{
public:
    inline FcgiAgent()
    {
        alive = false;
        thread = nullptr;
        FCGX_Init();
    }

    inline ~FcgiAgent()
    {
        stop();
    }

    struct Config
    {
        string local_host;
        int local_port;
        std::function<void(FcgiRequest)> handler;
    };

    inline int start(const Config &conf)
    {
        string local_path = conf.local_host + ":" + std::to_string(conf.local_port);

        sock = FCGX_OpenSocket(local_path.c_str(), SOMAXCONN);
        if (sock < 0)
            return 1;

        config = conf;
        alive = true;
        thread = new std::thread(entry, this);
        return 0;
    }

    inline void stop()
    {
        if (alive)
        {
            alive = false;
            thread->join();
        }
    }

private:
    bool alive;
    std::thread *thread;
    util::Logger logger;
    Config config;
    int sock;

    static void entry(FcgiAgent *agent)
    {
		while (agent->alive)
		{
		    FCGX_Request fcgx_req;
            FCGX_InitRequest(&fcgx_req, agent->sock, 0);
			if (FCGX_Accept_r(&fcgx_req) >= 0)
				agent->config.handler(FcgiRequest{fcgx_req});
		}
    }
};

#endif //TEMPLE_THIRD_FASTCGI_H_
